package net.liteheaven.xblib.widget.surfaceview;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import net.liteheaven.XbApp;
import net.liteheaven.xblib.R;
import net.liteheaven.xblib.common.image.BmpLruCache;
import net.liteheaven.xblib.common.log.XLog;
import net.liteheaven.xblib.common.ui.DimensionUtil;

import java.util.LinkedList;
import java.util.Random;

/**
 * 飘心SurfaceView
 */
public class FloatSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

    /**
     * 浮动图元
     */
    public class FloatUnit{
        private static final int ScaleDistance = 100;
        public float x;
        public float y;
        public int color;
        // 振幅，范围∈[-1,1]
        public float amplitude;
        // 速度，范围∈[1,5]
        public float speed;
        private Bitmap bmp;
        
        public FloatUnit(int color){
        	this.bmp = mUnitBitmap;
        	x = (int)(Math.random() * (getWidth() - mUnitBitmap.getWidth()) + mUnitBitmap.getWidth() / 2);
            y = getHeight();
            float speedFrom = DimensionUtil.dip2px(getContext(), 0.25f);
            float speedTo = DimensionUtil.dip2px(getContext(), 3f);
            speed = (float)(Math.random()) * speedFrom + (speedTo-speedFrom);
            amplitude = (float) (Math.random() * 2 - 1f);
            this.color = color;
        }

        public int getAlpha(){

            // 容器视图高度
            float h = getHeight();

            // Y入口检查
            float curY = y;
            if (curY<0){
                curY = 0;
            }
            if (curY>h){
                curY = h;
            }

            // 反转进度
            float reverse = h-curY;

            // alpha比率
            float percentage;
            if (reverse <= h/2.0f){
                percentage = .8f;
            }else{
                percentage = (h - reverse) / (h/2.0f) * .8f;
            }

            int alpha = (int)(percentage * 255);
            return alpha;
        }

        public float getScale(){

            // 容器视图高度
            float h = getHeight();

            // Y入口检查
            float curY = y;
            if (curY<0){
                curY = 0;
            }
            if (curY>h){
                curY = h;
            }

            // 反转进度
            float reverse = h-curY;

            // 计算压缩比率
            float percentage;
            if (reverse>ScaleDistance){
                percentage = 1;
            }else{
                percentage = reverse / ScaleDistance;
            }
            return percentage;
        }

        private int getLeft(){
            return (int)getX()-getDstWidth()/2;
        }

        private int getRight(){
            return (int)getX()+getDstWidth()/2;
        }

        private int getTop(){
            return (int)getY()-getDstHeight() /2;
        }

        private int getBottom(){
            return (int)getY()+getDstHeight()/2;
        }

        public Rect getSrcRect(){
            return new Rect(0,0,bmp.getWidth(),bmp.getHeight());
        }

        public Rect getDstRect(){
            return new Rect(getLeft(), getTop(), getRight(), getBottom());
        }
        
        private int getX(){
        	return (int) x;
        }
        
        private int getY(){
        	return (int) y;
        }

        private int getDstWidth(){
            return (int)(bmp.getWidth() * getScale() +.5f);
        }

        private int getDstHeight(){
            return (int)(bmp.getHeight() * getScale() +.5f);
        }
        
        public void move(){
        	y-=speed;        	
        	// x0:移动的路程比率[0,1]
        	float x0 = (getHeight()-y)/getHeight();
        	// y0:x方向偏移比率[0,1]
        	// y0 = -4(x0)² + 4(x0)
        	float y0 = -4 * x0 * x0 + 4 * x0;
        	// r:x方向最大偏移，为视图中心到图元在边缘刚好没有被遮挡位置的中心的距离
        	float r = getWidth() / 2 - mUnitBitmap.getWidth() / 2;
        	x = getWidth() / 2 + y0 * r * amplitude;
        }
    }

    /**
     * SurfaceView绘制线程
     */
    public class DrawThread extends Thread {

        private boolean terminate = false;

        @Override
        public void run() {
            super.run();

            while (!terminate) {
            	drawView();
                try {
                    Thread.sleep(Frequency);
                } catch (Exception e) {
                    break;
                }                
            }
        }

        public void fin(){
            terminate = true;
            try {
                this.join(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static class HeartGenerator {
    	
    	private Bitmap mUnitBitmap;
    	private Bitmap mUnitBitmap1;
    	private Paint mPaint;
    	private Rect mDrawSrcRect;
    	private BmpLruCache<String> mBitmapCache = new BmpLruCache<String>(0.3f);

    	public HeartGenerator(){
    		init();
    	}
    	
    	private void init(){
    		Context ctx = XbApp.getInstance().getContext();
    		mUnitBitmap = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.heart);
    		mUnitBitmap1 = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.heart1);
    		mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mDrawSrcRect = new Rect(0,0,mUnitBitmap.getWidth(),mUnitBitmap.getHeight());
    	}
    	
    	public Bitmap getBitmap(int color){
            String uri = ""+color;
            Bitmap bmp = mBitmapCache.get(uri, false);
            if (bmp == null){
                bmp = genBitmap(color);
                mBitmapCache.add(uri, bmp);
            }
            return bmp;
        }

        private Bitmap genBitmap(int color){
            Bitmap bitmap = mUnitBitmap.copy(Bitmap.Config.ARGB_8888, true);
            Bitmap bitmap1 = mUnitBitmap1;

            Canvas canvas = new Canvas(bitmap);

            Paint paint = mPaint;
            paint.setColor(color);
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            canvas.drawPaint(paint);

            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
            canvas.drawBitmap(bitmap1, mDrawSrcRect, mDrawSrcRect, paint);

            return bitmap;
        }
        
        public static int genColor(){
            final int color[] = {
                0xCCC3909E,
                0xCCD8B9F0,
                0xCCB6D38B,
                0xCCB8F2EE,
                0xCCD7C33C,
                0xCCAB5B71,
                0xCCF16E79,
                0xCCB8F2CC,
                0xCCF55165,
                0xCCDBFF92,
                0xCCF1B9E3,
                0xCCFD7E35,
                0xCCB8F2EE,
            };
            
            return color[new Random().nextInt(color.length)];
            //return Color.argb(255, (int) (Math.random() * 256), (int) (Math.random() * 256), (int) (Math.random() * 256));
        }
    }


    private final String TAG = "FloatSurfaceView";
    private final int Frequency = 10;
    private SurfaceHolder mSurfaceHolder;
    private Canvas mCanvas;
    private LinkedList<FloatUnit> mFloatUnits = new LinkedList<FloatUnit>();
    private DrawThread mDrawThread;
    private Bitmap mUnitBitmap;
    private HeartGenerator mHeartGenerator;

    public FloatSurfaceView(Context context) {
        super(context);
        initView();
    }

    public FloatSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public FloatSurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }
    
    public void resume() {
        XLog.i(TAG, "resume");
        initView();
    }
    
    public void setHeartGenerator(HeartGenerator hg) {
    	mHeartGenerator = hg;
    }

    @TargetApi(Build.VERSION_CODES.ECLAIR)
    private void initView() {
        if (isInEditMode()) {
            return;
        }

        mSurfaceHolder = getHolder();
        // 设置Holder类型,该类型表示surfaceView自己不管理缓存区,虽然提示过时，但最好还是要设置
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // 设置surface回调
        mSurfaceHolder.addCallback(this);

        XLog.i(TAG, "initView mSurfaceHolder="+mSurfaceHolder.toString());

        setZOrderOnTop(true);
        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);

        // 图元位图
        mUnitBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heart);
    }

    private synchronized void drawView(){    	
    	if (mSurfaceHolder == null){
    		return;
    	}

        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            drawImpl(mCanvas);
        } catch (Exception e) {        	
        } finally{
            if (mCanvas != null){
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    private void drawImpl(Canvas canvas){

        // 清空画布
        Paint paintClear = new Paint();
        paintClear.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawPaint(paintClear);

        // 绘图画刷
        Paint paintDraw = new Paint();
        paintDraw.setAntiAlias(true);

        for (int i = mFloatUnits.size()-1; i>=0; --i){

            // 图元
            FloatUnit floatUnit = mFloatUnits.get(i);

            // 绘图
            Bitmap curUnitBmp = mHeartGenerator.getBitmap(floatUnit.color);
            Rect rectSrc = floatUnit.getSrcRect();
            Rect rectDst = floatUnit.getDstRect();
            paintDraw.setAlpha(floatUnit.getAlpha());
            canvas.drawBitmap(curUnitBmp, rectSrc, rectDst, paintDraw);

            floatUnit.move();
            if (floatUnit.y + curUnitBmp.getHeight() < 0){
                mFloatUnits.remove(floatUnit);
            }
        }
    }

    private void startThread(){
    	XLog.i(TAG, "startThread");
        if (mDrawThread == null){
            mDrawThread = new DrawThread();
            mDrawThread.start();
        }
    }

    private void stopThread(){
    	XLog.i(TAG, "stopThread");
        if (mDrawThread != null){
            mDrawThread.fin();
            mDrawThread = null;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    	XLog.i(TAG, "surfaceCreated");
    	
    	if (mHeartGenerator == null){
    		throw new IllegalStateException("mHeartGenerator is null!");
    	}
    	
    	// 刚可见时清空数据
    	clearUnit();
        startThread();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    	XLog.i(TAG, "surfaceDestroyed");
        stopThread();
        mSurfaceHolder = null;
    }

    public synchronized void addUnit(FloatUnit floatUnit){
        mFloatUnits.add(floatUnit);
    }
    
    public synchronized void clearUnit(){
    	mFloatUnits.clear();
    }
    
    public void addUnit(int color) {
    	if (mFloatUnits.size() >= 100000){
    		return;
    	}
    	
        if (color == 0) {
            color = HeartGenerator.genColor();
        }
        FloatSurfaceView.FloatUnit floatUnit = new FloatSurfaceView.FloatUnit(color);
        addUnit(floatUnit);
    }
}
